#include "tcp_server.h"
#include "tcp_client.h"

void handle_cb(struct ev_loop *loop, ev_io *w, int revents)
{
    Client* client = (Client*)w->data;
    string message = receiveMessage(client->fd);
    int len = message.size();
    if (len > 0) 
    {
        // 接收成功，服务端在原基础上加上一个？并发送回去
        char client_ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &(client->addr.sin_addr), client_ip, INET_ADDRSTRLEN);
        int client_port = ntohs(client->addr.sin_port);

        cout << "【client:" << client_ip << ":" << client_port << " 】# " << message << endl;
        char response[BUFFER_SIZE];
        snprintf(response, BUFFER_SIZE, "%s?", message.c_str());
        sendMessage(client->fd, response);
        cout << "server send successful" << endl;
    } 
    else if (len == 0) 
    { // 表示对端关闭了连接
        char client_ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &(client->addr.sin_addr), client_ip, INET_ADDRSTRLEN);
        int client_port = ntohs(client->addr.sin_port);
        cout << client_ip << ":" << client_port << " closed the connection" << endl;
        // 关闭客户端套接字
        close(client->fd);
        // 停止对应的 ev_io 观察器
        ev_io_stop(loop, w);
        // 释放 Client 结构体
        delete client;
        // 释放 ev_io 观察器
        delete w;
    } 
    else 
    { // 返回-1表示接收失败
        cerr << "recv failed" << endl;
        // 关闭客户端套接字
        close(client->fd);
        ev_io_stop(loop, w);
        delete client;
        delete w;
    }
}

void accept_cb(struct ev_loop *loop, ev_io *w, int revents)
{
    // 如果是可读事件
    if (revents & EV_READ)
    {
        struct sockaddr_in c_addr;
        socklen_t c_len = sizeof(c_addr);
        int c_fd = accept(w->fd, (struct sockaddr*)&c_addr, &c_len);
        if (c_fd == -1) 
        {
            cerr << "accept failed" << endl;
            return;
        }

        // 将客户端的IP地址转换为字符串
        char c_ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &(c_addr.sin_addr), c_ip, INET_ADDRSTRLEN);
        int c_port = ntohs(c_addr.sin_port);

        cout << "Client connected: " << c_ip << ":" << c_port << endl;

        // 创建一个ev_io观察器用于处理客户端的读事件
        ev_io* c_watcher = new ev_io();
        c_watcher->fd = c_fd;
        c_watcher->data = new Client{c_fd, c_addr};
        ev_io_init(c_watcher, handle_cb, c_fd, EV_READ);
        ev_io_start(loop, c_watcher);
    }
}

int TcpServer::start()
{
    // 创建一个事件循环
    struct ev_loop *loop = EV_DEFAULT;

    // 创建套接字
    s_fd = socket(AF_INET, SOCK_STREAM, 0); // 使用ipv4和tcp
    if(s_fd == -1)
    {
        // 创建套接字失败
        cerr << "socket failed" << endl;
        return -1;
    }

    // 设置端口复用选项
    int opt = 1;
    if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) == -1) 
    {
        cerr << "Failed to set socket options" << endl;
        close(s_fd);
        return -1;
    }

    struct sockaddr_in s_addr;
    s_addr.sin_family = AF_INET; // ipv4
    // 使用htonl和htons将本机的字节序转化为网络字节序
    // host to net short/long 分别处理16位和32位的字节序
    s_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY自动获取本机ip地址
    s_addr.sin_port = htons(_port);

    if(bind(s_fd, (struct sockaddr*)&s_addr, sizeof(s_addr)) == -1)
    {
        // bind传参需要struct sockaddr的指针，这里使用的对象是ipv4的sockaddr_in，需要强转
        // bind成功返回0，失败返回-1
        cerr << "bind failed" << endl;
        return -2;
    }

    if(listen(s_fd, 10) == -1)
    {
        // listen成功返回0，失败返回-1
        cerr << "listen failed" << endl;
        return -3;
    }

    cout << "Server is listening on port 8080" << endl;

    // 创建一个ev_io对象来监听套接字的可读事件
    ev_io accept_watch;
    // 初始化并绑定相应回调处理函数
    ev_io_init(&accept_watch, accept_cb, s_fd, EV_READ);
    // 启动后意味着观察者将在accept变为可读后触发并调用回调函数
    ev_io_start (loop, &accept_watch);
    // 开始事件循环
    ev_run (loop, 0);

    close(s_fd);

    return 0;
}

